﻿using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using ServiceKit;
using ServiceKit.Extensions;
using ServiceKit.JsonRpc;
using ServiceKit.WebApi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Builder
{
    public static class BuilderExtensions
    {


        public static IMvcBuilder AddJsonRpc(this IMvcBuilder builder)
        {
            var configuration = RpcContants.RpcConfig ?? throw new ArgumentNullException(nameof(RpcContants.RpcConfig));
            var rpcService = GetAopServices();
            var rpcServiceInterface = new List<Type>();
            IMemoryCache cache = new MemoryCache(new MemoryCacheOptions());
            builder.Services.AddSingleton(cache);

            foreach (var item in rpcService)
            {
                var interfaceType = item.GetTypeInfo().GetInterfaces()[0];
                //if (interfaceType.IsValidedAopService(cache))
                //{
                rpcServiceInterface.Add(interfaceType);
                builder.Services.AddTransient(typeof(IService), item);
                builder.Services.TryAddTransient(interfaceType, item);
                //}
            }

            builder.Services
                .AddSingleton<ActionAuditFilterAttribute>()
                .Configure<RpcServerConfiguration>((options => { options = configuration; }))
                .AddSingleton<IHttpContextAccessor, HttpContextAccessor>()
                .AddSingleton<IRpcInvoker, DefaultRpcInvoker>();

            builder.ConfigureApplicationPartManager(manager =>
            {
                var controllers = rpcServiceInterface.Select(x => typeof(DynamicApiController<>).MakeGenericType(x)).ToList();
                manager.ApplicationParts.Add(new DynamicApiControllerApplicationPart(controllers.Select(x => x.GetTypeInfo())));
            });

            builder.AddJsonOptions(opts =>
            {
                //解决Json 序列化循环引用问题.
                opts.SerializerSettings.Converters = configuration.JsonSerializerSettings.Converters;
                opts.SerializerSettings.ReferenceLoopHandling = configuration.JsonSerializerSettings.ReferenceLoopHandling;
            });

            return builder;
        }

        public static IApplicationBuilder UseJsonRpc(this IApplicationBuilder app)
        {
            GlobalHttpContext.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());
            return app;
        }
        private static List<Type> GetAopServices()
        {
            //List<Assembly> loadableAssemblies = new List<Assembly>();
            List<Type> matchServices = new List<Type>();

            //if (loadableAssemblies.Count == 0)
            //{
            //    var deps = DependencyContext.Default;

            //    foreach (var compilationLibrary in deps.RuntimeLibraries)
            //    {
            //        try
            //        {
            //            var assembly = Assembly.Load(new AssemblyName(compilationLibrary.Name));
            //            loadableAssemblies.Add(assembly);
            //        }
            //        catch (Exception ex)
            //        {
            //            continue;
            //        }
            //    }
            //}
            //if (matchServices.Count == 0)
            //{
            //    foreach (var assembly in loadableAssemblies)
            //    {
            var services = Assembly.GetEntryAssembly().GetTypes()
                                  .Where(p => typeof(IService).IsAssignableFrom(p) && !p.GetTypeInfo().IsInterface)
                                  .Select(p => p);
            matchServices.AddRange(services);
            //    }
            //}
            return matchServices;
        }

        private static List<Type> GetServices()
        {
            //List<Assembly> loadableAssemblies = new List<Assembly>();
            List<Type> matchServices = new List<Type>();

            //if (loadableAssemblies.Count == 0)
            //{
            //    var deps = DependencyContext.Default;

            //    foreach (var compilationLibrary in deps.RuntimeLibraries)
            //    {
            //        try
            //        {
            //            var assembly = Assembly.Load(new AssemblyName(compilationLibrary.Name));
            //            loadableAssemblies.Add(assembly);
            //        }
            //        catch (Exception ex)
            //        {
            //            continue;
            //        }
            //    }
            //}
            //if (matchServices.Count == 0)
            //{
            //    foreach (var assembly in loadableAssemblies)
            //    {
            var services = Assembly.GetEntryAssembly().GetTypes()
                                  .Where(p => typeof(IService).IsAssignableFrom(p) && !p.GetTypeInfo().IsInterface)
                                  .Select(p => p);
            matchServices.AddRange(services);
            //    }
            //}
            return matchServices;
        }
    }
}
